package com.open.capacity.finance.service.impl;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.open.capacity.finance.dao.*;
import com.open.capacity.finance.dto.AuditModelBaseResult;
import com.open.capacity.finance.dto.SourceZcfzbErrorDto;
import com.open.capacity.finance.dto.ZcfzbDto;
import com.open.capacity.finance.dto.audit_model_26.AuditModelResult;
import com.open.capacity.finance.dto.audit_model_26.ExcelData;
import com.open.capacity.finance.entity.*;
import com.open.capacity.finance.service.AbstractAuditMakeResultFactory;
import com.open.capacity.finance.service.AuditModelRuleService;
import com.open.capacity.finance.service.AuditModelService;
import com.open.capacity.finance.util.FileUtil;
import com.open.capacity.user.model.SysCompany;
import com.open.capacity.user.service.SysCompanyService;
import com.open.capacity.utils.StringUtil;
import com.open.capacity.utils.encrypt.Md5Utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class AuditModelActuator26ServiceImpl<T extends AuditModelBaseResult> extends AbstractAuditMakeResultFactory {

    @Autowired
    private AuditAnalysisDao analysisDao;

    @Autowired
    private SourceBaseKjkmExtDao kjkmExtDao;
    @Autowired
    private SourceBaseCustomItemDao customItemDao;
    @Autowired
    private SourceBaseCustomValueDao customValueDao;

    @Autowired
    private SourceBaseFinalaccountTotal8Dao finalaccountTotal8Dao;

    @Autowired
    private AuditModelRuleService ruleService;
    @Autowired
    private AuditModelService modelService;

    @Autowired
    private SysCompanyService companyService;
    @Autowired
    private SourceKmyeDao kmyeDao;


    @Override
    protected T analyseResultData(String modelId, Map param) {
        String companyId = param.containsKey("companyId") ? param.get("companyId").toString() : "";
        param.put("ztId", "101");//101
        AuditModelResult result = new AuditModelResult();
        AuditModel model = modelService.findById(modelId);
        Assert.notNull(model, "找不到该模型");
        List<AuditModelRule> rules = ruleService.findByModelId(modelId);

        rules.forEach(t -> {
            if (t.getConfKey().equals("zys") || t.getConfKey().equals("noZys") || t.getConfKey().equals("jjflcodes")) {
                param.put(t.getConfKey(), t.getConfValue().split(","));
            } else {
                param.put(t.getConfKey(), t.getConfValue());
            }
        });
        result.setModelName(model.getCodeAndName());
        List errorList = checkData(param);
        result.setCompanyId(companyId);
        result.setStep1List(errorList);
        if (CollectionUtils.isEmpty(errorList)) {
            result.setExists(0);
        } else {
            result.setExists(1);

            //持久化本地
            persistence(result);
        }

        return (T) result;
    }

    private List<SourceZcfzbErrorDto> checkData(Map<String, Object> params) {
        String companyId = params.containsKey("companyId") ? params.get("companyId").toString() : "";
        List<SourceKmye> dtoList = kmyeDao.findAll(params);
        List<SourceBaseFinalaccountTotal8> zcfzbList = finalaccountTotal8Dao.findAll(params);

        //遍历全部机构
        Map<String, Object> param = new HashMap<>();
        if (StringUtil.isNotEmpty(companyId) && !companyId.equals("-1")) {
            param.put("id", companyId);
        }
        List<SysCompany> companys = companyService.findAll(param);
        List<SourceZcfzbErrorDto> errorList = new ArrayList<>();
        for (SysCompany company : companys) {
            //库存资金
            BigDecimal money_total_ncye = BigDecimal.ZERO;
            BigDecimal money_total_ye = BigDecimal.ZERO;
            //资产合计
            BigDecimal zc_total_ncye = BigDecimal.ZERO;
            BigDecimal zc_total_ye = BigDecimal.ZERO;
            //负债合计
            BigDecimal fz_total_ncye = BigDecimal.ZERO;
            BigDecimal fz_total_ye = BigDecimal.ZERO;
            //净资产合计
            BigDecimal jzc_total_ncye = BigDecimal.ZERO;
            BigDecimal jzc_total_ye = BigDecimal.ZERO;

            //4
            BigDecimal total_ncye4 = BigDecimal.ZERO;
            BigDecimal total_ye4 = BigDecimal.ZERO;

            //5
            BigDecimal total_ncye5 = BigDecimal.ZERO;
            BigDecimal total_ye5 = BigDecimal.ZERO;

            //总计
            BigDecimal zj_total_ncye = BigDecimal.ZERO;
            BigDecimal zj_total_ye = BigDecimal.ZERO;

            List<ZcfzbDto.ItemValue> kmyeList = new ArrayList<>();

            if (CollectionUtils.isNotEmpty(dtoList.stream().filter(t -> t.getCompanyId().equals(company.getId())).collect(Collectors.toList()))) {
                for (SourceKmye item : dtoList.stream().filter(t -> t.getCompanyId().equals(company.getId())).collect(Collectors.toList())) {
                    if (item.getKjkmCode().startsWith("1")) {
                        if (item.getKjqj().equals(0)) {
                            zc_total_ncye = zc_total_ncye.add(item.getD().subtract(item.getJ()));
                        }
                        zc_total_ye = zc_total_ye.add(item.getD()).subtract(item.getJ());

                        if ((item.getKjkmCode().startsWith("1001") || item.getKjkmCode().startsWith("1002")) && !item.getKjkmCode().equals("10020401") && !item.getKjkmCode().equals("10020402")) {
                            if (item.getKjqj().equals(0)) {
                                money_total_ncye = money_total_ncye.add(item.getD().add(item.getJ()));
                            }
                            money_total_ye = money_total_ye.add(item.getD()).subtract(item.getJ());
                        }
                    } else if (item.getKjkmCode().startsWith("2")) {
                        if (item.getKjqj().equals(0)) {
                            fz_total_ncye = fz_total_ncye.add(item.getJ().subtract(item.getD()));
                            zj_total_ncye = zj_total_ncye.add(item.getJ().subtract(item.getD()));
                        }
                        fz_total_ye = fz_total_ye.add(item.getJ()).subtract(item.getD());
                        zj_total_ye = zj_total_ye.add(item.getJ()).subtract(item.getD());

                    } else if (item.getKjkmCode().startsWith("4")) {
                        if (item.getKjqj().equals(0)) {
                            total_ncye4 = total_ncye4.add(item.getJ().subtract(item.getD()));
                        }
                        total_ye4 = total_ye4.add(item.getJ()).subtract(item.getD());
                    } else if (item.getKjkmCode().startsWith("5")) {
                        if (item.getKjqj().equals(0)) {
                            total_ncye5 = total_ncye5.add(item.getJ().subtract(item.getD()));
                        }
                        total_ye5 = total_ye5.add(item.getJ()).subtract(item.getD());
                    } else if (item.getKjkmCode().startsWith("3")) {
                        if (!item.getKjkmCode().equals("331")) {
                            if (item.getKjqj().equals(0)) {
                                jzc_total_ncye = jzc_total_ncye.add(item.getJ().subtract(item.getD()));
                            }
                            jzc_total_ye = jzc_total_ye.add(item.getJ()).subtract(item.getD());
                        }
                    }

                    ZcfzbDto.ItemValue dto = new ZcfzbDto.ItemValue();
                    dto.setKjkmCode(item.getKjkmCode());
                    dto.setKjkmName(item.getKjkmName());
                    dto.setNcye(item.getQm());
                    dto.setYe(item.getYe());
                    kmyeList.add(dto);
                }
                boolean exists = false;
                for (ZcfzbDto.ItemValue item : kmyeList) {
                    if (item.getKjkmCode().equals("331")) {
                        exists = true;
                        item.setNcye(item.getNcye().add(total_ncye4).subtract(total_ncye5));
                        item.setYe(item.getYe().add(total_ye4).subtract(total_ye5));

                        jzc_total_ncye = jzc_total_ncye.add(item.getNcye()).add(total_ncye4).subtract(total_ncye5);
                        jzc_total_ye = jzc_total_ye.add(item.getYe());

                        zj_total_ncye = zj_total_ncye.add(jzc_total_ncye);
                        zj_total_ye = zj_total_ye.add(jzc_total_ye);
                    }
                }
                if (!exists) {
                    ZcfzbDto.ItemValue dto = new ZcfzbDto.ItemValue();
                    dto.setKjkmCode("331");
                    dto.setKjkmName("结余");
                    dto.setNcye(total_ncye4.subtract(total_ncye5));
                    dto.setYe(total_ye4.subtract(total_ye5));
                    kmyeList.add(dto);
                }
                ZcfzbDto.ItemValue dto = new ZcfzbDto.ItemValue();
                dto.setKjkmCode("zc_total");
                dto.setKjkmName("资产合计");
                dto.setNcye(zc_total_ncye);
                dto.setYe(zc_total_ye);
                kmyeList.add(dto);

                dto = new ZcfzbDto.ItemValue();
                dto.setKjkmCode("fz_total");
                dto.setKjkmName("负债合计");
                dto.setNcye(fz_total_ncye);
                dto.setYe(fz_total_ye);
                kmyeList.add(dto);

                dto = new ZcfzbDto.ItemValue();
                dto.setKjkmCode("jzc_total");
                dto.setKjkmName("净资产合计");
                dto.setNcye(jzc_total_ncye);
                dto.setYe(jzc_total_ye);
                kmyeList.add(dto);

                dto = new ZcfzbDto.ItemValue();
                dto.setKjkmCode("zj_total");
                dto.setKjkmName("总计");
                dto.setNcye(zj_total_ncye);
                dto.setYe(zj_total_ye);
                kmyeList.add(dto);
            }


            Optional<SourceBaseFinalaccountTotal8> money = zcfzbList.stream().filter(t -> t.getCompanyId().equals(company.getId()) && t.getKjkmName().trim().equals("货币资金")).findFirst();
            Optional<SourceBaseFinalaccountTotal8> zc = zcfzbList.stream().filter(t -> t.getCompanyId().equals(company.getId()) && t.getKjkmName().equals("一、资产合计")).findFirst();
            Optional<SourceBaseFinalaccountTotal8> fz = zcfzbList.stream().filter(t -> t.getCompanyId().equals(company.getId()) && t.getKjkmName().equals("二、负债合计")).findFirst();
            Optional<SourceBaseFinalaccountTotal8> jzc = zcfzbList.stream().filter(t -> t.getCompanyId().equals(company.getId()) && t.getKjkmName().equals("三、净资产合计")).findFirst();

            if (money.isPresent()) {
                if (money.get().getNcye().compareTo(money_total_ncye) != 0 || money.get().getYe().compareTo(money_total_ye) != 0) {
                    SourceZcfzbErrorDto errorDto = new SourceZcfzbErrorDto();
                    errorDto.setCompanyId(money.get().getCompanyId());
                    errorDto.setCompanyName(money.get().getCompanyName());
                    errorDto.setKjnd(money.get().getKjnd());
                    errorDto.setErrorCode(11);
                    errorDto.setNcye1(money.get().getNcye());
                    errorDto.setNcye2(money_total_ncye);
                    errorDto.setYe1(money.get().getYe());
                    errorDto.setYe2(money_total_ye);
                    errorDto.setErrorMsg("货币资金数据不一致");
                    errorList.add(errorDto);
                }
            }
            if (zc.isPresent()) {
                if (zc.get().getNcye().compareTo(zc_total_ncye) != 0 || zc.get().getYe().compareTo(zc_total_ye) != 0) {
                    SourceZcfzbErrorDto errorDto = new SourceZcfzbErrorDto();
                    errorDto.setCompanyId(zc.get().getCompanyId());
                    errorDto.setCompanyName(zc.get().getCompanyName());
                    errorDto.setKjnd(zc.get().getKjnd());
                    errorDto.setErrorCode(1);
                    errorDto.setNcye1(zc.get().getNcye());
                    errorDto.setNcye2(zc_total_ncye);
                    errorDto.setYe1(zc.get().getYe());
                    errorDto.setYe2(zc_total_ye);
                    errorDto.setErrorMsg("资产合计数据不一致");
                    errorList.add(errorDto);
                }
            }
            if (fz.isPresent()) {
                if (fz.get().getNcye().compareTo(fz_total_ncye) != 0 || fz.get().getYe().compareTo(fz_total_ye) != 0) {
                    SourceZcfzbErrorDto errorDto = new SourceZcfzbErrorDto();
                    errorDto.setCompanyId(fz.get().getCompanyId());
                    errorDto.setCompanyName(fz.get().getCompanyName());
                    errorDto.setKjnd(fz.get().getKjnd());
                    errorDto.setErrorCode(2);
                    errorDto.setNcye1(fz.get().getNcye());
                    errorDto.setNcye2(fz_total_ncye);
                    errorDto.setYe1(fz.get().getYe());
                    errorDto.setYe2(fz_total_ye);
                    errorDto.setErrorMsg("负债合计数据不一致");
                    errorList.add(errorDto);
                }
            }
            if (jzc.isPresent()) {
                if (jzc.get().getNcye().compareTo(jzc_total_ncye) != 0 || jzc.get().getYe().compareTo(jzc_total_ye) != 0) {
                    SourceZcfzbErrorDto errorDto = new SourceZcfzbErrorDto();
                    errorDto.setCompanyId(jzc.get().getCompanyId());
                    errorDto.setCompanyName(jzc.get().getCompanyName());
                    errorDto.setKjnd(jzc.get().getKjnd());
                    errorDto.setErrorCode(3);
                    errorDto.setNcye1(jzc.get().getNcye());
                    errorDto.setNcye2(jzc_total_ncye);
                    errorDto.setYe1(jzc.get().getYe());
                    errorDto.setYe2(jzc_total_ye);
                    errorDto.setErrorMsg("净资产合计数据不一致");
                    errorList.add(errorDto);
                }
            }
        }
        return errorList;
    }

    @Override
    protected int persistence(AuditModelBaseResult data) {
        int result = 0;

        String content = JSON.toJSONString(data, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue,
                SerializerFeature.WriteDateUseDateFormat);

        data.setResultFileMd5(Md5Utils.hash(content));
        data.setResultFileUrl("/upload/analyse/model26_" + data.getCompanyId() + "_" + data.getResultFileMd5() + ".json");

        Writer write = null;
        try {
            File file = new File(fileuploadPath + "/upload/analyse/model26_" + data.getCompanyId() + "_" + data.getResultFileMd5() + ".json");
            if (file.exists()) {
                file.delete();
            }
            file.createNewFile();
            // 写入文件
            write = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8);
            write.write(content);
            write.flush();
            write.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                write.close();
            } catch (IOException e) {
                log.error(e.getMessage());
            }
        }
        return result;
    }

    @Override
    public T getData(String modelId, Map param) {
        return analyseResultData(modelId, param);
    }


    /**
     * 从本地加载数据
     */
    public AuditModelBaseResult getDataFromJson(String jsonUrl, Map param) {
        AuditModelResult result = null;
        try {
            String json = FileUtil.readTxtToJson(fileuploadPath + jsonUrl);
            result = JSONObject.parseObject(json, new TypeReference<AuditModelResult>() {
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
        filterCondition(result, param);

        return result;
    }

    /**
     * 本地json数据条件过滤
     */
    private AuditModelResult filterCondition(AuditModelResult orig, Map param) {
        AuditModelResult result = orig;
        String companyId = MapUtils.getString(param, "companyId");
        Integer kjnd = MapUtils.getInteger(param, "kjnd");

        List<SourceZcfzbErrorDto> list = orig.getStep1List();
        if (StringUtil.isNotEmpty(companyId)) {
            list = list.stream().filter(t -> t.getCompanyId().equals(companyId)).collect(Collectors.toList());
        }
        if (kjnd != null) {
            list = list.stream().filter(t -> t.getKjnd().equals(kjnd)).collect(Collectors.toList());
        }

        result.setStep1List(list);

        return result;
    }

    public void exportExcel(String modelId, Map params, HttpServletResponse response) {
        AuditModelResult t = (AuditModelResult) analyseResultData(modelId, params);

        export(t, response);
    }

    @Override
    public void exportExcelFromJson(String modelId, String jsonUrl, HttpServletResponse response) {
        AuditModelResult t = null;
        try {
            String json = FileUtil.readTxtToJson(fileuploadPath + jsonUrl);
            t = JSONObject.parseObject(json, new TypeReference<AuditModelResult>() {
            });
        } catch (Exception e) {
            e.printStackTrace();
        }

        export(t, response);
    }

    private void export(AuditModelResult t, HttpServletResponse response) {
        List<ExcelData> result = t.getStep1List().stream().map(item -> {
            ExcelData model = new ExcelData();
            BeanUtils.copyProperties(item, model);
            return model;
        }).collect(Collectors.toList());

        response.setContentType("application/vnd.ms-excel");
        response.setHeader("Content-disposition", "attachment;filename=download_26.xls");
        OutputStream ouputStream = null;
        Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(),
                ExcelData.class, result);
        try {
            ouputStream = response.getOutputStream();
            workbook.write(ouputStream);
        } catch (Exception e) {
            throw new RuntimeException("系统异常");
        } finally {
            try {
                if (ouputStream != null) {
                    ouputStream.flush();
                    ouputStream.close();
                }
            } catch (Exception e) {
                throw new RuntimeException("系统异常");
            }
        }
    }
}
